package com.allprs.common.aspect;

import com.allprs.common.annotation.SysDict;
import com.allprs.common.constant.CacheConstants;
import com.allprs.common.core.domain.AjaxResult;
import com.allprs.common.core.domain.entity.SysDictData;
import com.allprs.common.core.page.TableDataInfo;
import com.allprs.common.core.redis.RedisCache;
import com.allprs.common.utils.bean.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 操作日志记录处理
 *
 * @author cim
 */
@Aspect
@Component
public class SysDictAspect implements Ordered {
    private static final Logger log = LoggerFactory.getLogger(SysDictAspect.class);

    private Map<String, String> dictInfoMap = new ConcurrentHashMap<>();

    @Autowired
    private RedisCache redisService;

    /**
     * 切入点所有的controller
     */
    @Pointcut("execution( * com.allprs.*.controller.*.*(..))")
    public void doSysDict(){

    }

    /**
     * 字典翻译
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("execution( * com.allprs.*.controller.*.*(..))")
    public Object translatian(final ProceedingJoinPoint pjp) throws Throwable{
        Object result = pjp.proceed();
        if(result == null){
            return result;
        }

        //获取实体类
        Object obj = null;

        //目前只针对系统返回的这三种结果集进行处理，并且返回的结果只能是list<vo>或者vo
        if(result instanceof TableDataInfo){
            //分页返回的结果集
            TableDataInfo ret = (TableDataInfo) result;
            List<?> rows = ret.getRows();
            if(rows == null || rows.size() == 0){
                return result;
            }
            obj = rows.get(0);
        }else if(result instanceof AjaxResult){
            AjaxResult ret = (AjaxResult) result;
            Object data = ret.get("data");
            if(data == null){
                return result;
            }
            if(data instanceof List || data instanceof ArrayList){
                List rList = (List) data;
                if(rList == null || rList.size() == 0){
                    return result;
                }
                obj = rList.get(0);
            }else{
                obj = data;
            }

        }else{
            return result;
        }

        /**
         * 获取翻译字段配置信息
         */
        Map<String, SysDict> dataDictMap = boDict(obj.getClass());
        if (dataDictMap.size() == 0) {
            return result;
        }

        /**
         * 获取字典信息
         */
        this.getCodeInfo();

        if(result instanceof TableDataInfo){
            //分页返回的结果集
            TableDataInfo ret = (TableDataInfo) result;
            List<?> rows = ret.getRows();
            for (Object o : rows) {
                sign(o, dataDictMap, dictInfoMap);
            }
        }else if(result instanceof AjaxResult){
            AjaxResult ret = (AjaxResult) result;
            Object data = ret.get("data");
            if(data instanceof List || data instanceof ArrayList){
                //返回的结果是list或者arraylist
                for (Object o : (List) data) {
                    sign(o, dataDictMap, dictInfoMap);
                }
            }else{
                sign(data, dataDictMap, dictInfoMap);
            }
        }
        return result;
    }


    /**
     * 获取bo中属性值
     *
     * @param cla
     * @return
     */
    private Map<String, SysDict> boDict(Class cla) {
        Field[] fields = cla.getDeclaredFields();
        Map<String, SysDict> map = new HashMap<String, SysDict>();
        for (Field field : fields) {
            if (field.isAnnotationPresent(SysDict.class)) {
                SysDict dataDict = field.getAnnotation(SysDict.class);
                String fieldName = field.getName();
                map.put(fieldName, dataDict);
            }
        }
        return map;
    }

    /**
     * 获取数据字典
     */
    public void getCodeInfo() throws Exception {
        List<SysDictData> dictList = redisService.getCacheByPrefix(CacheConstants.SYS_DICT_KEY);

        List<SysDictData> dictInfos;
        //缓存中没有重新从数据库中取
        if (dictList == null || dictList.size() == 0) {
            //避免循环依赖，不取数据库
//            R<List<SysDictData>> r = remoteDictService.getAllCode(SecurityConstants.INNER);
//            dictInfos = r.getData();
            return;
        } else {
            dictInfos = dictList;
        }
        if (dictInfos == null || dictInfos.size() == 0) {
            return;
        }
        //把字典值转成map
        for (SysDictData dictData : dictInfos) {
            dictInfoMap.put(dictData.getDictType() + dictData.getDictValue(), dictData.getDictLabel());
        }
    }


    /**
     * 单个设置值
     *
     * @param obj
     * @param dataDictMap 注解字段
     * @param dictInfoMap
     */
    public void sign(Object obj, Map<String, SysDict> dataDictMap, Map<String, String> dictInfoMap) {

        for (Map.Entry<String, SysDict> entry : dataDictMap.entrySet()) {
            String fileName = entry.getKey();
            SysDict dataDict = entry.getValue();
            this.setCode(obj, dataDict, fileName, dictInfoMap);
        }
    }


    /**
     * 设置字典值
     *
     * @param obj
     * @param dataDict    属性的注解字段配置
     * @param fileName    需要赋值的字段
     * @param dictInfoMap 字典信息数据
     * @throws Exception
     */
    public void setCode(Object obj, SysDict dataDict, String fileName, Map<String, String> dictInfoMap) {
        if (dictInfoMap == null || dictInfoMap.size() == 0) {
            return;
        }
        //字典类型
        String dictType = dataDict.dictType();
        //字典来源
        String source = dataDict.source();

        if (StringUtils.isNotBlank(dictType)) {
            try {
                //字典value
                String sourceValue = (String) BeanUtils.getBeanFieldValue(obj.getClass(), obj, source);
                //字典值 翻译后的值
                String dictCodeName = null;
                if (StringUtils.isNotBlank(sourceValue)) {
                    dictCodeName = dictInfoMap.get(dictType + sourceValue);
                    BeanUtils.setBeanField(obj.getClass(), obj, fileName, dictCodeName);
                    return;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else{
            return;
        }
    }

    /**
     * 内部服务调用验证处理前执行
     * @return
     */
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 3;
    }
}
